package easier.recycler;

import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import easier.recycler.MultiTypeAdapter.MultiTypeHolder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 创建多类型adapter,recyclerView
 * 将数据包装成显示数据,然后设置给该adapter,根据显示数据创建界面
 */
public class MultiTypeAdapter extends Adapter< MultiTypeHolder > {

    /**
     * 所有界面数据
     */
    protected final List< TypeViewHolder > mViewHolders = new ArrayList<>();

    /**
     * 创建没有数据界面
     */
    public MultiTypeAdapter() {

    }

    /**
     * @param viewHolders 创建该界面数据
     */
    public MultiTypeAdapter( List< TypeViewHolder > viewHolders ) {

        mViewHolders.clear();
        mViewHolders.addAll( viewHolders );
    }

    /**
     * 获取该viewHolder的索引数据
     *
     * @param viewHolder 获取索引的数据
     *
     * @return 位置信息
     */
    public int indexOf( TypeViewHolder viewHolder ) {

        return mViewHolders.indexOf( viewHolder );
    }

    /**
     * @param viewHolders 更新界面数据
     */
    public void updateViewHolders( List< TypeViewHolder > viewHolders ) {

        List< TypeViewHolder > old = new ArrayList<>( mViewHolders );
        List< TypeViewHolder > newData = new ArrayList<>( viewHolders );

        mViewHolders.clear();
        mViewHolders.addAll( viewHolders );

        DiffUtil.Callback diff = createDiffCallBack( old, newData );
        DiffUtil.calculateDiff( diff ).dispatchUpdatesTo( this );
    }

    public void updateViewHolder( int index, TypeViewHolder viewHolder ) {

        mViewHolders.set( index, viewHolder );
        notifyItemChanged( index );
    }

    public void updateViewHolders( int positionStart, List< TypeViewHolder > viewHolders ) {

        for ( int i = 0; i < viewHolders.size(); i++ ) {
            TypeViewHolder viewHolder = viewHolders.get( i );
            int index = positionStart + i;
            if ( index < mViewHolders.size() ) {
                mViewHolders.set( index, viewHolder );
            } else {
                mViewHolders.add( viewHolder );
            }
        }

        notifyItemRangeChanged( positionStart, viewHolders.size() );
    }

    public void notifyViewHolderChanged( TypeViewHolder typeViewHolder ) {

        notifyItemChanged( mViewHolders.indexOf( typeViewHolder ) );
    }

    public void notifyViewHolderChanged( TypeViewHolder typeViewHolder, @Nullable Object payload ) {

        notifyItemChanged( mViewHolders.indexOf( typeViewHolder ), payload );
    }

    /**
     * @param viewHolder 增加数据
     */
    public void addViewHolder( TypeViewHolder viewHolder ) {

        addViewHolder( mViewHolders.size(), viewHolder );
    }

    /**
     * @param index      增加数据
     * @param viewHolder view holder
     */
    public void addViewHolder( int index, TypeViewHolder viewHolder ) {

        mViewHolders.add( index, viewHolder );
        notifyItemInserted( index );
    }

    /**
     * @param viewHolders 增加数据
     */
    public void addViewHolders( List< TypeViewHolder > viewHolders ) {

        addViewHolders( mViewHolders.size(), viewHolders );
    }

    /**
     * 增加数据
     *
     * @param start       起始位置
     * @param viewHolders 数据
     */
    public void addViewHolders( int start, List< TypeViewHolder > viewHolders ) {

        mViewHolders.addAll( start, viewHolders );
        notifyItemRangeInserted( start, viewHolders.size() );
    }

    /**
     * 删除指定位置数据
     *
     * @param position
     */
    public void removeViewHolder( int position ) {

        mViewHolders.remove( position );
        notifyItemRemoved( position );
    }


    public void removeViewHolder( TypeViewHolder viewHolder ) {

        int i = mViewHolders.indexOf( viewHolder );
        if ( i >= 0 ) {
            removeViewHolder( i );
        }
    }

    public void removeViewHolders( int positionStart, int itemCount ) {

        mViewHolders.subList( positionStart, positionStart + itemCount ).clear();
        notifyItemRangeRemoved( positionStart, itemCount );
    }

    public void moveViewHolder( int fromPosition, int toPosition ) {

        Collections.swap( mViewHolders, fromPosition, toPosition );
        notifyItemMoved( fromPosition, toPosition );
    }

    /**
     * 创建一个{@link RecyclerView.ViewHolder},该holder仅起到作用:连接显示数据{@link TypeViewHolder}和{@link MultiTypeAdapter}
     */
    @NonNull
    @Override
    public MultiTypeHolder onCreateViewHolder( @NonNull ViewGroup parent, int viewType ) {
        /* 创建指定类型的view,注意:该view和创建者不是绑定的关系 */
        View view = getViewForType( parent, viewType );
        return new MultiTypeHolder( view );
    }

    /**
     * 将界面数据{@link TypeViewHolder}绑定到显示界面{@link RecyclerView.ViewHolder#itemView}
     *
     * @param holder   显示界面
     * @param position 界面位置
     */
    @Override
    public void onBindViewHolder( @NonNull MultiTypeHolder holder, int position ) {

        /* 将创建的view绑定数据 */
        TypeViewHolder viewHolder = mViewHolders.get( position );
        holder.setTypeViewHolder( viewHolder );
        viewHolder.onBind( holder, holder.itemView, position, viewHolder.getType(), Collections.emptyList() );
    }

    @Override
    public void onBindViewHolder( @NonNull MultiTypeHolder holder, int position, @NonNull List< Object > payloads ) {

        /* 将创建的view绑定数据 */
        TypeViewHolder viewHolder = mViewHolders.get( position );
        holder.setTypeViewHolder( viewHolder );
        viewHolder.onBind( holder, holder.itemView, position, viewHolder.getType(), payloads );
    }

    /**
     * @param holder 解绑界面数据,可以释放资源
     */
    @Override
    public void onViewRecycled( @NonNull MultiTypeHolder holder ) {

        /* 将创建的view解绑数据 */
        TypeViewHolder data = holder.getTypeViewHolder();
        if ( data != null ) {
            data.onUnBind( holder, holder.itemView, holder.getAdapterPosition() );
            holder.setTypeViewHolder( null );
        }
    }

    /**
     * 通知界面数据界面已经离开window
     *
     * @param holder 界面
     */
    @Override
    public void onViewDetachedFromWindow( @NonNull MultiTypeHolder holder ) {

        super.onViewDetachedFromWindow( holder );
        TypeViewHolder data = holder.getTypeViewHolder();
        if ( data != null ) {
            data.onDetachedFromWindow( holder, holder.itemView );
        }
    }

    @Override
    public void onViewAttachedToWindow( @NonNull MultiTypeHolder holder ) {

        super.onViewAttachedToWindow( holder );
        TypeViewHolder data = holder.getTypeViewHolder();
        if ( data != null ) {
            data.onAttachedToWindow( holder, holder.itemView );
        }
    }

    @Override
    public int getItemCount() {

        return mViewHolders.size();
    }

    @Override
    public int getItemViewType( int position ) {
        /* 获取类型,用于创建复用 */
        return mViewHolders.get( position ).getType();
    }

    /**
     * 创建指定类型的view
     *
     * @param parent parent
     * @param type   类型
     *
     * @return view
     */
    protected View getViewForType( ViewGroup parent, int type ) {

        for ( TypeViewHolder holder : mViewHolders ) {
            if ( holder.getType() == type ) {
                /* 创建指定类型的view,注意:该view和创建者不是绑定的关系 */
                /* 创建的view不会设置给TypeViewHolder,再复用过程中设置给TypeViewHolder */
                View view = holder.generateView( parent );
                holder.onViewCreate( view );
                return view;
            }
        }
        return new View( parent.getContext() );
    }

    protected DiffUtil.Callback createDiffCallBack( List< TypeViewHolder > old, List< TypeViewHolder > newList ) {

        return new TypeViewHolderDiffCallBack( old, newList );
    }


    /**
     * 辅助创建,只用于创建回收{@link MultiTypeAdapter#getViewForType(ViewGroup, int)}创建的view
     */
    public static class MultiTypeHolder extends ViewHolder {

        /**
         * {@link MultiTypeAdapter#onBindViewHolder(MultiTypeHolder, int)}中设置对应数据到此处
         */
        private TypeViewHolder mTypeViewHolder;

        public MultiTypeHolder( @NonNull View itemView ) {

            super( itemView );
        }

        /* 私有使用,不对外使用 */
        protected void setTypeViewHolder( TypeViewHolder typeViewHolder ) {

            mTypeViewHolder = typeViewHolder;
        }

        protected TypeViewHolder getTypeViewHolder() {

            return mTypeViewHolder;
        }
    }

    /**
     * 工具方法,通知界面有变化
     *
     * @param adapter adapter
     * @param list    所有界面
     * @param item    变化界面
     */
    public static void notifyAdapterItemChanged( RecyclerView.Adapter< ? > adapter, List< TypeViewHolder > list, TypeViewHolder item ) {

        notifyAdapterItemChanged( adapter, list, item, 0 );
    }

    /**
     * 工具方法,通知界面有变化
     *
     * @param adapter adapter
     * @param list    所有界面
     * @param item    变化界面
     */
    public static void notifyAdapterItemChanged( RecyclerView.Adapter< ? > adapter, List< TypeViewHolder > list,
        TypeViewHolder item, int offset ) {

        int i = list.indexOf( item );
        if ( i >= 0 ) {
            adapter.notifyItemChanged( i + offset );
        }
    }

    /**
     * 工具方法,通知界面有变化
     *
     * @param adapter adapter
     * @param list    所有界面
     * @param item    变化界面
     * @param changed 变化的数据
     */
    public static void notifyAdapterItemChanged( RecyclerView.Adapter< ? > adapter, List< TypeViewHolder > list,
        TypeViewHolder item, Object changed ) {

        notifyAdapterItemChanged( adapter, list, item, changed, 0 );
    }

    /**
     * 工具方法,通知界面有变化
     *
     * @param adapter adapter
     * @param list    所有界面
     * @param item    变化界面
     * @param changed 变化的数据
     */
    public static void notifyAdapterItemChanged( RecyclerView.Adapter< ? > adapter, List< TypeViewHolder > list,
        TypeViewHolder item, Object changed, int offset ) {

        int i = list.indexOf( item );
        if ( i >= 0 ) {
            adapter.notifyItemChanged( i + offset, changed );
        }
    }
}